package edu.washington.ling.syntric.io;

import java.util.List;
import java.util.LinkedList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.regex.*;
import java.util.Set;
import java.io.RandomAccessFile;
import java.io.IOException;

public class TreeFileReaderSGML extends TreeFileReader {
	
	private RandomAccessFile f;
	private HashMap<String, Long> treeLocations;
	private Iterator<String> treeIDIterator;
	private static Pattern startPattern = Pattern.compile("\\<Sentence id\\s*\\=\\s*[\"\']?([^.\"\'\\s]+)(\\.ssf)?\\s*[\"\']?\\>");
	private static Pattern endPattern = Pattern.compile("\\<\\/Sentence\\>");
	
	
	public TreeFileReaderSGML(String path, String layer) throws IOException {
		super(path, layer);
		f = new RandomAccessFile(path, "r");
		List<String> treeIDs = new LinkedList<String>();
		treeLocations = new HashMap<String, Long>();
		String line = null;
		while ((line = f.readLine()) != null) {
			Matcher m = startPattern.matcher(line);
			if (m.matches()) {
				String id = m.group(1);
				if (treeLocations.containsKey(id)) {
					String errStr = String.format("Warning: The tree id \'%s\' appears multiple times in '%s'.\n" +
							"Only the first instance was processed\n", id, path);
					System.err.println(errStr);
				}
				else {
					treeIDs.add(id);
					treeLocations.put(id, f.getFilePointer());
				}
			}
		}
		treeIDIterator = treeIDs.iterator();
	}
	@Override
	public int numTrees() {
		return treeLocations.size();
	}
	@Override
	public Set<String> getIDs() {
		return treeLocations.keySet();
	}
	@Override
	public TreeRepresentation readNextTreeRep() throws IOException {
		TreeRepresentation tr = null;
		Long location, lineLength;
		byte[] bytes;
		if (treeIDIterator.hasNext()) {
			String id = treeIDIterator.next();
			List<String> treeLines = new LinkedList<String>();
			location = treeLocations.get(id);
			f.seek(location.longValue());
			String line = null;
			while ((line = f.readLine()) != null){ 
				lineLength = f.getFilePointer() - location;
				bytes = new byte[lineLength.intValue()];
				f.seek(location);
				f.read(bytes);
				line = new String(bytes, "UTF8").replaceAll("[\r\n\f]+", "");
				location += lineLength;
				f.seek(location);
				if (endPattern.matcher(line).matches()) { break; }
				else { treeLines.add(line); }
			}
			tr = new TreeRepresentation(treeLines, this.getLayer());
		}
		return tr;
	}

	@Override
	public boolean hasTreeRepWithID(String id) {
		return treeLocations.containsKey(id);
	}
	@Override
	public TreeRepresentation readTreeRepWithID(String id) throws IOException {
		TreeRepresentation tr = null;
		Long location, lineLength;
		byte[] bytes;
		if (treeLocations.containsKey(id)) {
			List<String> treeLines = new LinkedList<String>();
			location = treeLocations.get(id);
			f.seek(location.longValue());
			String line = null;
			while ((line = f.readLine()) != null){
				lineLength = f.getFilePointer() - location;
				bytes = new byte[lineLength.intValue()];
				f.seek(location);
				f.read(bytes);
				line = new String(bytes, "UTF8").replace("\n","");
				location += lineLength;
				f.seek(location);
				if (endPattern.matcher(line).matches()) { break; }
				else { treeLines.add(line); }
			}
			tr = new TreeRepresentation(treeLines, this.getLayer());
		}
		return tr;
	}
}
